<?php

namespace addons\kzvote\library;

use EasyWeChat\Factory;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use EasyWeChat\Kernel\Support\Collection;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Message\ResponseInterface;
use think\Exception;

/**
 * 微信公众号、小程序服务
 */
class WechatService
{
    /**
     * 微信配置信息
     * @return array
     */
    private static function getConfig(): array
    {

        $wxapp = kzvote_getConfig('wxapp');
        if (!isset($wxapp['app_id']) || !$wxapp['app_id']) {
            throw new Exception('缺少appid配置');
        }
        if (!isset($wxapp['secret']) || !$wxapp['secret']) {
            throw new Exception('缺少secret配置');
        }
        if (!isset($wxapp['mchid']) || !$wxapp['mchid']) {
            throw new Exception('缺少mchid配置');
        }
        if (!isset($wxapp['key']) || !$wxapp['key']) {
            throw new Exception('缺少key配置');
        }

        return [
            'app_id' => $wxapp['app_id'],
            'secret' => $wxapp['secret'],
            'mch_id' => $wxapp['mchid'],
            'key'    => $wxapp['key'],
        ];
    }

    /**
     * 公众号配置信息
     * @return array
     */
    private static function getWechatConfig(): array
    {

        $wechat = kzvote_getConfig('wechat');
        if (!isset($wechat['wechat_app_id']) || !$wechat['wechat_app_id']) {
            throw new Exception('缺少appid配置');
        }
        if (!isset($wechat['wechat_secret']) || !$wechat['wechat_secret']) {
            throw new Exception('缺少secret配置');
        }
        if (!isset($wechat['wechat_mchid']) || !$wechat['wechat_mchid']) {
            throw new Exception('缺少mchid配置');
        }
        if (!isset($wechat['wechat_key']) || !$wechat['wechat_key']) {
            throw new Exception('缺少key配置');
        }

        return [
            'app_id' => $wechat['wechat_app_id'],
            'secret' => $wechat['wechat_secret'],
            'mch_id' => $wechat['wechat_mchid'],
            'key'    => $wechat['wechat_key'],

            'oauth' => [
                'scopes' => ['snsapi_userinfo'],
            ],
        ];
    }

    /**
     * 获取支付回调地址
     * @return string
     */
    private static function getPayNotifyUrl($platform): string
    {
        return request()->domain() . '/addons/kzvote/notify/'.$platform;
    }

    /**
     * 公众号实例
     * @return \EasyWeChat\OfficialAccount\Application
     */
    public static function getApp(): \EasyWeChat\officialAccount\Application
    {
        return Factory::officialAccount(self::getWechatConfig());
    }

    /**
     * 小程序实例
     * @return \EasyWeChat\MiniProgram\Application
     */
    public static function getMiniApp(): \EasyWeChat\MiniProgram\Application
    {
        return Factory::miniProgram(self::getConfig());
    }

    /**
     * 支付实例
     * @return \EasyWeChat\Payment\Application
     */
    public static function getPayment($platform = 'wxapp'): \EasyWeChat\Payment\Application
    {
        $config = Factory::payment($platform=='wxapp'?self::getConfig():self::getWechatConfig());
        // $config['cert_path'] = APP_PATH . '/common/certs/apiclient_cert.pem';
        // $config['key_path']  = APP_PATH . '/common/certs/apiclient_key.pem';
        return $config;
    }

    /**
     * H5发起登录
     * @param array $params 回调参数
     * @param int $type 授权方式
     * @return array
     */
    public function login()
    {
        $app = self::getApp();
        $oauth = $app->oauth;
        // return $oauth->user()->toArray()["original"];
        return $oauth->userFromCode(request()->get("code"))->toArray();
    }

    public function jssdk($url){
        $app = self::getApp();
        $app->jssdk->setUrl($url);
        return $app->jssdk->buildConfig(['onMenuShareTimeline','onMenuShareAppMessage','hideOptionMenu','chooseWXPay','wx-open-launch-weapp','wx-open-subscribe'], $debug = false, $beta = false, $json = false);
    }

    /**
     * 小程序登录
     * @param string $code 前端js code
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function miniLogin(string $code)
    {
        $app = self::getMiniApp();
        return $app->auth->session($code);
    }

    /**
     * 统一支付
     * @param string $openid 用户open id
     * @param string $out_trade_no 订单编号
     * @param int $fee 订单金额
     * @param string $body 订单说明
     * @param string $attach
     * @return array|Collection|object|ResponseInterface|string
     * @throws InvalidArgumentException
     * @throws InvalidConfigException
     * @throws GuzzleException
     */
    public function unifyPay(string $platform, string $openid, string $out_trade_no, int $fee, string $body)
    {
        $payment = self::getPayment($platform);

        $result = $payment->order->unify([
            'body'         => $body,
            'out_trade_no' => $out_trade_no,
            'total_fee'    => $fee,
            'trade_type'   => 'JSAPI',
            'openid'       => $openid,
            'notify_url'   => self::getPayNotifyUrl($platform),
        ]);

        if ($result['return_code'] == 'FAIL') {
            throw new Exception('发起支付失败：' . $result['return_msg']);
        }

        return $payment->jssdk->bridgeConfig($result['prepay_id'], false);
    }

    /**
     * 微信小程序消息解密
     * 比如获取电话等功能，信息是加密的，需要解密
     * @param $session
     * @param $iv
     * @param $encryptedData
     * @return mixed
     */
    public function decryptedData($session, $iv, $encryptedData)
    {
        $app = self::getMiniApp();
        return $app->encryptor->decryptData($session, $iv, $encryptedData);
    }

    /**
     * 文本安全内容检测
     * @param $content
     * @return bool
     */
    public function contentSecurity($content)
    {
        $app = self::getMiniApp();
        $result = $app->content_security->checkText($content);
        if ($result['errcode'] == 0){
            return true;
        }
        return false;
    }

    /**
     * 图片安全内容检测
     * 需要绝对路径
     * @param $url
     * @return bool
     */
    public function checkImage($url)
    {
        $app = self::getMiniApp();
        $result = $app->content_security->checkImage($url);
        if ($result['errcode'] == 0){
            return true;
        }
        return false;
    }

}
